package mt.dummy;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ConnectException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import javax.swing.JOptionPane;
import mt.Order;
import mt.comm.ClientComm;
import mt.comm.ClientSideMessage;
import mt.comm.ServerSideMessage;
import mt.comm.ServerSideMessage.Type;

/**
 * ClientCommDummy is used by the GUI of the client to communicate with the
 * server.
 *
 * @author Pedro,Rita,Miguel
 *
 */
public class ClientCommDummy implements ClientComm {

	private Socket socket;
	private Receive rcv;
	private ObjectOutputStream out;
	private ObjectInputStream in;
	private final BlockingQueue<ClientMessage> q = new ArrayBlockingQueue<ClientMessage>(100);
	private String nickname;


	@Override
	public void connect(String serverAddress, String nickname) {

		this.nickname = nickname;
		try {
			socket = new Socket(serverAddress.split(":")[0], Integer.parseInt(serverAddress.split(":")[1]));
			in = new ObjectInputStream(socket.getInputStream());

			out = new ObjectOutputStream(socket.getOutputStream());
			ServerMessage msg = new ServerMessage(ServerSideMessage.Type.CONNECTED, nickname, null);
			out.writeObject(msg);
			rcv = new Receive(in);
			rcv.start();
			System.out.println("<" + nickname + "> Connection to server established!");
		} catch (UnknownHostException e) {
			System.out.println("<" + nickname + "> Error: Unknown server.");
			JOptionPane.showMessageDialog(null, "Unknown server.",
					"MicroTrader", JOptionPane.ERROR_MESSAGE);
			return;
		} catch (ConnectException e) {
			System.out.println("<" + nickname + "> Error: Connection refused from server.");
			JOptionPane.showMessageDialog(null, "Connection refused from server.",
					"MicroTrader", JOptionPane.ERROR_MESSAGE);
			return;
		} catch (IOException e) {
			e.printStackTrace();
		}
	}



	@Override
	public boolean isConnected() {
		if(socket == null)
			return false;
		return socket.isConnected();
	}

	@Override
	public void disconnect() {
		if(socket != null && socket.isConnected()){
			try {
				ServerMessage msg = new ServerMessage(Type.DISCONNECTED, nickname, null);
				out.writeObject(msg);
				out.close();
				in.close();
				socket.close();
				rcv.STOP_SIGNAL = true;
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	@Override
	public boolean hasNextMessage() {
		return !q.isEmpty();
	}

	@Override
	public ClientSideMessage getNextMessage() {
		return q.poll();
	}

	@Override
	public void sendOrder(Order order) {
		try {
			out.writeObject((new ServerMessage(ServerSideMessage.Type.NEW_ORDER, nickname, order)));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * This Threads receives and processed the ClientMessage.
	 */
	class Receive extends Thread {

		public boolean STOP_SIGNAL = false;
		private final ObjectInputStream in;

		public Receive(ObjectInputStream in) {
			this.in = in;
		}

		@Override
		public void run() {
			try {
				while (socket.isConnected() && !STOP_SIGNAL) {
					ClientMessage msg = (ClientMessage) in.readObject();
					q.add(msg);
				}
			} catch (IOException e) {

			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			}
		}
	}

}
